package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.exception.CreateProjectException;
import com.heima.model.common.constants.NewsAutoScanConstants;
import com.heima.model.common.constants.WemediaContants;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.dtos.WmNewsDto;
import com.heima.model.wemedia.dtos.WmNewsPageReqDto;
import com.heima.model.wemedia.pojos.WmMaterial;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmNewsMaterial;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.EmptyUtil;
import com.heima.utils.threadlocal.WmThreadLocalUtils;
import com.heima.wemedia.mapper.WmMaterialMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmNewsMaterialMapper;
import com.heima.wemedia.service.WmNewsService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {

    @Value("${file.oss.web-site}")
    String website;
    @Autowired
    WmNewsMaterialMapper wmNewsMaterialMapper;
    @Autowired
    WmMaterialMapper wmMaterialMapper;
    @Autowired
    KafkaTemplate kafkaTemplate;
    /**
     * 根据文章id查询文章
     *
     * @param id
     * @return
     */
    @Override
    public ResponseResult findWmNewsById(Integer id) {
        if(id==null){
            CreateProjectException.exec(AppHttpCodeEnum.PARAM_INVALID);
        }
        //2 执行查询
        WmNews wmNews = getById(id);
        if (wmNews == null) {
            CreateProjectException.exec(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //3 返回结果
        ResponseResult result = ResponseResult.okResult(wmNews);
        result.setHost(website);
        return result;
    }

    /**
     * 删除文章
     *
     * @param id
     * @return
     */
    @Override
    public ResponseResult delNews(Integer id) {
        //1.判断参数是否有效
        if(id==null){
            CreateProjectException.exec(AppHttpCodeEnum.PARAM_INVALID);
        }
        //2.查看数据是否存在
        WmNews wmNews = getById(id);
        if(EmptyUtil.isNullOrEmpty(wmNews)){
            CreateProjectException.exec(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //3.查看该新闻状态是否已发布
        if(wmNews.getStatus().equals(WmNews.Status.PUBLISHED.getCode()) && wmNews.getEnable().equals(WemediaContants.WM_NEWS_UPENABLE)){
            CreateProjectException.exec(AppHttpCodeEnum.WMNEWS_IS_ALREADY_PUTON);
        }
        //4。删除该新闻与素材库中间表中的数据
        wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery().eq(WmNewsMaterial::getNewsId,id));
        //5.删除新闻
        removeById(id);
        //6.返回结果
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 上下架
     * @param dto
     * @return
     */
    @Override
    public ResponseResult downOrUp(WmNewsDto dto) {
        //1.参数是否存在
        if(EmptyUtil.isNullOrEmpty(dto)||dto.getId()==null){
            CreateProjectException.exec(AppHttpCodeEnum.PARAM_INVALID);
        }
        //2.该新闻是否存在
        WmNews wmNews = getById(dto.getId());
        if(EmptyUtil.isNullOrEmpty(wmNews)){
            CreateProjectException.exec(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //3.判断该是否处于发布状态 非发布状态不能修改上下架
        if(!wmNews.getStatus().equals(WmNews.Status.PUBLISHED.getCode())){
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST,"当前文章不是发布状态，不能上下架");
        }
        // TODO 发送消息给APP端

        //4.同步文章状态
        if(dto.getEnable() != null && dto.getEnable() > -1 && dto.getEnable() < 2){
            update(Wrappers.<WmNews>lambdaUpdate().eq(WmNews::getId,dto.getId()).set(WmNews::getEnable,dto.getEnable()));
        }
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 分页带条件查询自媒体文章列表
     * @param dto
     * @return
     */
    @Override
    public ResponseResult findAll(WmNewsPageReqDto dto) {
        //1.校验参数
        if(EmptyUtil.isNullOrEmpty(dto)){
            CreateProjectException.exec(AppHttpCodeEnum.PARAM_INVALID);
        }
        dto.checkParam();
        Page<WmNews> page = new Page<>(dto.getPage(),dto.getSize());
        LambdaQueryWrapper<WmNews> wrapper = Wrappers.<WmNews>lambdaQuery();
        if(dto.getStatus() != null){
            wrapper.eq(WmNews::getStatus,dto.getStatus());
        }
        if(dto.getKeyWord()!=null){
            wrapper.like(WmNews::getTitle,dto.getKeyWord());
        }
        if(dto.getChannelId()!=null){
            wrapper.eq(WmNews::getChannelId,dto.getChannelId());
        }
        if(dto.getBeginPubdate()!=null&&dto.getEndPubdate()!=null){
            wrapper.between(WmNews::getPublishTime,dto.getBeginPubdate(),dto.getEndPubdate());
        }
        WmUser user = WmThreadLocalUtils.getUser();
        if(EmptyUtil.isNullOrEmpty(user)){
            wrapper.eq(WmNews::getUserId,user.getId());
        }
        wrapper.orderByDesc(WmNews::getCreatedTime);
        IPage<WmNews> pageResult = page(page, wrapper);
        PageResponseResult result = new PageResponseResult(dto.getPage(), dto.getSize(), (int) pageResult.getTotal());
        result.setData(pageResult.getRecords());
        result.setHost(website);
        return result;
    }

    /**
     * 自媒体文章发布
     * @param dto
     * @param isSubmit 是否为提交 1 为提交 0为草稿
     * @return
     */
    @Override
    public ResponseResult saveNews(WmNewsDto dto, Short isSubmit){
        //1.参数设定
        if(EmptyUtil.isNullOrEmpty(dto)){
            CreateProjectException.exec(AppHttpCodeEnum.PARAM_INVALID);
        }
        //2.构造修改文章
        WmNews wmNews = new WmNews();
        try {
            BeanUtils.copyProperties(dto,wmNews);
        } catch (Exception e) {
            CreateProjectException.exec(AppHttpCodeEnum.PARAM_COPY_ERROR);
        }
        //2.1解析内容 得出内容中的图片集合
        String content = dto.getContent();
        List<Map> contentImages = JSON.parseArray(content, Map.class);
        // 当前的内容中的图片集合
        List<String> materials = parseContentImages(contentImages);
        //2.2整合两种情况（自动配置封面图片 和 手动选择封面图片） 添加好了wmNews对象
        //返回修改过的 WmNews 文章对象
        wmNews = saveOrUpdateWmNews(dto, wmNews, materials);
        // 判断 如果是提交状态 就分别提交封面图与素材库关系 和 内容图与素材库的关系
        if(isSubmit.equals(WemediaContants.WM_NEWS_SUMMIT_STATUS)){
            if(wmNews.getImages()!=null ){
                List<String> meterialss = Arrays.asList(wmNews.getImages().split(","));
                saveMaterialToWmNewsMaterial(meterialss,wmNews.getId());
            }
            if(materials.size()>0){
                List<String> meterialss = Arrays.asList(parseImages(materials).split(","));
                saveImageToWmNewsMaterial(meterialss,wmNews.getId());
            }
        }
        // 4 发消息给admin审核文章
        Map map = new HashMap<String,Object>();
        map.put("wmNewsId", wmNews.getId());
        kafkaTemplate.send(NewsAutoScanConstants.WM_NEWS_AUTO_SCAN_TOPIC, JSON.toJSONString(map));

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 提交内容图与素材库之间的关系
     * @param meterials 当前提交素材
     * @param wmNewId 当前新闻的ID
     */
    private void saveMaterialToWmNewsMaterial(List<String> meterials, Integer wmNewId) {
        saveWmNewsMaterial(meterials,wmNewId,WemediaContants.WM_CONTENT_REFERENCE);
    }

    /**
     * 提交内容图与素材库之间的关系（执行方法）
     * @param meterials 素材
     * @param wmNewId  素材所属新闻ID
     * @param type 状态（封面图 or 内容图）
     */
    private void saveWmNewsMaterial(List<String> meterials, Integer wmNewId, Short type) {
        //通过 图片url地址和自媒体用户id 查询素材库表 获得对应的素材ID
        List<WmMaterial> dbmaterials = wmMaterialMapper.selectList(Wrappers.<WmMaterial>lambdaQuery()
                .in(WmMaterial::getUrl,meterials)
                .eq(WmMaterial::getUserId, WmThreadLocalUtils.getUser().getId()));
        if(dbmaterials==null||dbmaterials.size()==0){
            CreateProjectException.exec(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        Map<String, Integer> dbMap = dbmaterials.stream().collect(Collectors.toMap(WmMaterial::getUrl, WmMaterial::getId));
        //创建一个集合用作储存素材id
        ArrayList<Integer> materialIds = new ArrayList<>();
        //判断 该素材当前是否还存在
        for (String meterial : meterials) {
            Integer id = dbMap.get(meterial);
            if(id == null){
                CreateProjectException.exec(AppHttpCodeEnum.MATERIAL_IS_NOT_FOUND);
            }
            materialIds.add(id);
        }
        wmNewsMaterialMapper.saveMaterialMapper(materialIds,wmNewId,type);
    }

    /**
     * 提交封面图与素材库之间的关系
     * @param meterials 当前提交素材
     * @param wmNewId  当前新闻的ID
     */
    private void saveImageToWmNewsMaterial(List<String> meterials, Integer wmNewId) {
        saveWmNewsMaterial(meterials,wmNewId,WemediaContants.WM_IMAGE_REFERENCE);
    }

    /**
     * @param dto 传递来的前端参数
     * @param wmNews 处理过的基本文章对象
     * @param materials 图片信息集合
     */
    private WmNews saveOrUpdateWmNews(WmNewsDto dto, WmNews wmNews, List<String> materials) {
        String images = null;
        wmNews.setSubmitedTime(new Date());
        if(wmNews.getId()==null){//新增
            //设置初始参数
            wmNews.setCreatedTime(new Date());
            wmNews.setUserId(WmThreadLocalUtils.getUser().getId());
            wmNews.setEnable(WemediaContants.WM_NEWS_UPENABLE);
        }else {//修改
            //删除中间表数据
            wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery()
                    .eq(WmNewsMaterial::getNewsId, wmNews.getId()));
        }
        if(WemediaContants.WM_NEWS_TYPE_AUTO.equals(dto.getType())){
            //自动上传封面图片
            //数据库type字段类型为tyint 没办法接受-1
            dto.setType(null);
            //处理images值 从内容图片集合materials中获得String图片字符串
            //判断数据库内容中的图片数量
            if(materials.size()>0&&materials.size()<=2){
                images = parseImages(materials.stream().limit(1).collect(Collectors.toList())) ;
                wmNews.setType(WemediaContants.WM_NEWS_SINGLE_IMAGE);
                wmNews.setImages(images);
            }else if(materials.size()>2){
                images = parseImages(materials.stream().limit(3).collect(Collectors.toList()));
                wmNews.setType(WemediaContants.WM_NEWS_MANY_IMAGE);
                wmNews.setImages(images);
            }else{
                wmNews.setType(WemediaContants.WM_NEWS_NONE_IMAGE);
            }
        }else {
            //手动上传封面图片
            wmNews.setImages(parseImages(dto.getImages()));
        }
        saveOrUpdate(wmNews);
        return wmNews;
    }

    /**
     * 解析list 将前缀拆掉改为适合存储的形式
     * @param list
     * @return
     */
    private String parseImages(List<String> list) {
        return list.toString().replace("[","")
                .replace("]","")
                .replace(" ","")
                .replace(website,"");
    }

    /**
     * 规范方法 用于将文章内容中的图片信息拿出并组成list返回
     * @param contentImages
     * @return
     */
    private List<String> parseContentImages(List<Map> contentImages) {
        ArrayList<String> materials = new ArrayList<>();
        for (Map<String, String> contentImage : contentImages) {
            if(contentImage.get("type").equals("image")){
                materials.add(contentImage.get("value"));
            }
        }
        return materials;
    }
}













